/*
 * jxController Project (2014)
 * 
 * by Denilson Edinaldo Pinto
 * 
 * LGPL
 * Copyright (C) 2014
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.jxController;

import java.lang.reflect.Constructor;
import java.util.List;

import javax.swing.JDesktopPane;
import javax.swing.JOptionPane;

import org.jxController.event.GenericCrudEvent;
import org.jxController.i18n.I18N;
import org.jxController.view.CrudInternalFrame;
import org.jxDao.dao.DBManager;
import org.jxDao.dao.Dao;
import org.jxDao.dao.GenericDao;
import org.jxDao.dao.Persistable;
import org.jxUtils.ReflectionUtil;
import org.jxUtils.check.CheckUtil;

/**
 * @author Denilson Edinaldo Pinto
 * @porject jxController
 * @package org.jxController
 * @date 06/05/2014 - 00:24:11
 * @param <Bean>
 * @param <TView>
 * @param <TDao>
 */
public abstract class GenericController<Bean extends Persistable, TView extends CrudInternalFrame<Bean>, TDao extends Dao<Bean>> {
	
	private Class<?> beanClass;
	
	private Class<?> viewClass;
	
	private Class<?> daoClass;
	
	private TView view;
	
	private TDao dao;
	
	/**
	 * @param owner
	 * @param manager
	 * @throws Throwable
	 */
	public GenericController(final JDesktopPane owner, final DBManager manager) throws Throwable {
	
		init(manager, owner);
	}
	
	/**
	 * @param manager
	 * @param initargs
	 * @throws Throwable
	 */
	@SuppressWarnings("unchecked")
	private void init(final DBManager manager, final Object... initargs) throws Throwable {
	
		// Obtém as Classes do parâmetro
		final List<Class<?>> parameterClasses = ReflectionUtil.getParameterClass(getClass());
		
		beanClass = parameterClasses.get(0);
		viewClass = parameterClasses.get(1);
		daoClass = parameterClasses.get(2);
		
		//
		if(CheckUtil.isNotNullAndNotEmpty(initargs) && initargs.length > 0) {
			
			final Class<?>[] initargsClasses = new Class<?>[initargs.length];
			final Object[] objects = new Object[initargs.length];
			
			//
			for(int index = 0; index < initargs.length; index++) {
				
				initargsClasses[index] = initargs[index].getClass();
				objects[index] = initargs[index];
			}
			
			final Constructor<TView> viewConstructor = (Constructor<TView>)viewClass.getConstructor(initargsClasses);
			
			view = viewConstructor.newInstance(objects);
			
		}else {
			
			final Constructor<TView> viewConstructor = (Constructor<TView>)viewClass.getConstructor();
			
			view = viewConstructor.newInstance();
		}
		
		final Constructor<TDao> daoConstructor = (Constructor<TDao>)daoClass.getConstructor(DBManager.class);
		
		try {
			//
			dao = daoConstructor.newInstance(manager);
			
			Dao<?> gDao = DBManager.getDaoFromCache(beanClass);
			
			// 
			if(gDao != null && !gDao.getClass().getName().equals(daoClass.getName())) {
				
				DBManager.removeDaoFromCache(beanClass);
				
				DBManager.getDaoCache().put(beanClass, (GenericDao<Bean>)dao);
			}
			
		}catch(final Throwable throwable) {
			
			final String error = CheckUtil.isNullOrAbsoluteEmpty(throwable.getMessage()) ? throwable.getCause() == null ? throwable.toString() : throwable.getCause().getMessage() : throwable.getMessage();
			
			JOptionPane.showMessageDialog(null, I18N.controller().couldNotStartDAO(daoClass.getSimpleName(), error));
			
			throw throwable;
		}
		
		// 
		view.setCrudEvent(new GenericCrudEvent<Bean, TView, TDao>(view, dao));
		
		view.setIconifiable(true);
		view.setClosable(true);
		view.setVisible(true);
		view.centralize();
	}
	
	/**
	 * @return the beanClass
	 */
	public Class<?> getBeanClass() {
	
		return beanClass;
	}
	
	/**
	 * @return the dao
	 */
	public TDao getDao() {
	
		return dao;
	}
	
	/**
	 * @return the view
	 */
	public TView getView() {
	
		return view;
	}
}
